package cn.itsource.hrm.service.impl;

import cn.itsource.hrm.mapper.HighlightResultMapper;
import cn.itsource.hrm.query.CourseQuery;
import cn.itsource.hrm.repository.CourseDocTORepository;
import cn.itsource.hrm.service.ISearcherCourseService;
import cn.itsource.hrm.to.CourseDocTO;
import cn.itsource.hrm.util.CousreAggPageList;
import cn.itsource.hrm.util.PageList;
import cn.itsource.hrm.vo.AggreVo;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class SearcherCourseServiceImpl implements ISearcherCourseService {
    @Autowired
    CourseDocTORepository repository;

    @Autowired
    ElasticsearchTemplate template;

    @Autowired
    HighlightResultMapper resultMapper; // 高亮结果的转化器

    //ES 查询的步骤：
    // 1. 通过 repository 对象进行查询
    // 2. queryBuild 对象 NativeQueryBuilder；
    // 3. 判断查询条件
    // 4. 分页
    // 5. 排序
    // 6. 过滤
    // 7. 查询
    // 8. 高量
    // 9. 聚合;
    @Override
    public PageList<CourseDocTO> searchCourse(CourseQuery query) {
        NativeSearchQueryBuilder builder = new NativeSearchQueryBuilder();
        // 分页================= 注：分页起始从0开始的
        builder.withPageable(PageRequest.of(query.getPage()-1,query.getRows()));

        // 排序=================
        SortOrder order = SortOrder.DESC;
        if(query.getSortType()!=null){
            order = query.getSortType().equals("desc")? SortOrder.DESC : SortOrder.ASC;
        }

        String sortField = "price";
        if(query.getSortField()!=null){
            switch (query.getSortField()){
                case "xl":sortField="saleCount";break;
                case "xp":sortField="OnLineDate";break;
                case "pl":sortField="commentCount";break;
                case "jg":sortField="price";break;
                case "rq":sortField="viewCount";break;
                default:  sortField = "price";
            }
        }
        builder.withSort(SortBuilders.fieldSort(sortField).order(order));

        // 过滤和查询 ====================================
        BoolQueryBuilder booleanQuery = getBoolQueryBuilder(query);
        builder.withQuery(booleanQuery);

        // 高亮  ===================================
        HighlightBuilder.Field nameField = new HighlightBuilder.Field("name")
                .preTags("<b style='color:red'>").postTags("</b>");

        HighlightBuilder.Field tenantNameField = new HighlightBuilder.Field("tenantName")
                .preTags("<b style='color:red'>").postTags("</b>");

        builder.withHighlightFields(nameField,tenantNameField);


        // 聚合  ====================================
        TermsAggregationBuilder gradeNameTermerm = AggregationBuilders
                .terms("gradeName_term").field("gradeName").size(20);

        TermsAggregationBuilder tenantNameTerm = AggregationBuilders
                .terms("tenantName_term").field("tenantName").size(20);

        builder.addAggregation(gradeNameTermerm);
        builder.addAggregation(tenantNameTerm);

        // 执行查询
        // 要想执行高亮查询，需要用最原始Template
        AggregatedPage<CourseDocTO> page = template.queryForPage(builder.build(), CourseDocTO.class, resultMapper);

        //手动转换聚合的结果 -->  CousreAggPageList
        // aggrTenantNames
        //((StringTerms.Bucket) ((java.util.ArrayList)((StringTerms)((java.util.ArrayList)((InternalAggregations)((AggregatedPageImpl)page).aggregations).aggregations).get(0)).buckets).get(0)).getKeyAsNumber()
        StringTerms gradeNameTerm = (StringTerms) page.getAggregation("gradeName_term");
        // 我们想要的结果实际保存在 buckets 里
        List<StringTerms.Bucket> buckets = gradeNameTerm.getBuckets();
        // stream,流式编程
        // map : 把一个集合，转换为另外一个集合
        List<AggreVo> gradeNameList = buckets.stream()
                .map(bucket-> new AggreVo(bucket.getKeyAsString(),bucket.getDocCount()))
                .collect(Collectors.toList());

        // aggrGrades
        StringTerms tenantTerm = (StringTerms) page.getAggregation("tenantName_term");
        List<StringTerms.Bucket> tbuckets = tenantTerm.getBuckets();
        List<AggreVo> tenantNameList = new ArrayList<>();
        for (StringTerms.Bucket bucket : tbuckets) {
            tenantNameList.add(new AggreVo(bucket.getKeyAsString(),bucket.getDocCount()));
        }


        // 之前的 repository 不支持高亮
        // Page<CourseDocTO> page = repository.search(builder.build());
        CousreAggPageList<CourseDocTO> coursePageList = new CousreAggPageList<>(page.getTotalElements(), page.getContent());

        coursePageList.setAggrGrades(gradeNameList);
        coursePageList.setAggrTenantNames(tenantNameList);

        return coursePageList;

    }

    private BoolQueryBuilder getBoolQueryBuilder(CourseQuery query) {
        // 过滤查询 ====================================
        // 过滤是在所有的文档筛选结果 -- where X = #{x}
        // 查询是一个比较精确的关键字 -- 模糊的 like
        BoolQueryBuilder booleanQuery = QueryBuilders.boolQuery();
        // 过滤
        if(query.getCourseTypeId()!=null){
            booleanQuery.filter(QueryBuilders.termQuery("courseTypeId",query.getCourseTypeId()));
        }
        if(query.getGradeId()!=null){
            booleanQuery.filter(QueryBuilders.termQuery("gradeId",query.getGradeId()));
        }
        if(query.getTenantId()!=null){
            booleanQuery.filter(QueryBuilders.termQuery("tenantId",query.getTenantId()));
        }
        // 范围过滤
        if(query.getPriceMax()!=null){
            // 搜索 - 比最大范围小的
            booleanQuery.filter(QueryBuilders.rangeQuery("price").lte(query.getPriceMax()));
        }
        if(query.getPriceMin()!=null){
            // 搜索 - 比最小范围大的
            booleanQuery.filter(QueryBuilders.rangeQuery("price").gte(query.getPriceMin()));
        }


        // 范围查询
        // 关键字 keyword 查询,需求keyword 即可能是 name 也可能是tenantName 或者 descriprtion
//        booleanQuery.must(QueryBuilders.matchQuery("name",query.getKeyword()));
//        booleanQuery.must(QueryBuilders.matchQuery("tenantName",query.getKeyword()));
//        booleanQuery.must(QueryBuilders.matchQuery("description",query.getKeyword()));
        if(StringUtils.isNotBlank(query.getKeyword())){
            booleanQuery.must(QueryBuilders.multiMatchQuery(query.getKeyword()
                    ,"name","tenantName","description"));
        }else{
            booleanQuery.must(QueryBuilders.matchAllQuery());
        }
        return booleanQuery;
    }
}
